package storage.v1;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;

import com.onpositive.data.IPropertyConstants;
import com.onpositive.knowledge.model.IThing;
import com.onpositive.mediawiki.propertyparser.ParsedCategory;
import com.onpositive.mediawiki.propertyparser.ParsedDocument;
import com.onpositive.mediawiki.propertyparser.PropertyCharacteristic;
import com.onpositive.semantic.model.api.realm.IRealm;
import com.onpositive.units.ParsedProperty;
import com.onpositive.wikistorage.XMLInterface;

abstract public class LowLevelStorage extends CategoryStorage  {
	
	/**
	 * 
	 */		
	private static final long serialVersionUID = 4113935258921633398L;

	public static String RAW_DATA_FILE_NAME = "raw data.xml" ;
	
	protected ParserV2 parser ;
	protected RawTextReferencesStorage references ;
	String rootPath;
	
	public LowLevelStorage(String path){
		this.rootPath = path.trim();
		this.rootPath += this.rootPath.endsWith("/") ? "" : "/" ;
		
		category = XMLInterface.loadParsedCategory( this.rootPath + RAW_DATA_FILE_NAME );
		if( category == null )
			category = new ParsedCategory( this.rootPath ) ;
		
		parser = new ParserV2() ;
		references = new RawTextReferencesStorage(path) ;
	}

	protected void reparseDocument( String id, ReplacementRequest request, int flags )
	{
		//id = "list1";// table extraction test //
		ParsedDocument oldDoc = category.getParsedDocument(id) ;
		String documentContent = references.getContent( id, flags ) ;
		
		ParsedDocument newDoc = new ParsedDocument();
		newDoc.setName(id) ;
		newDoc.setCategory(category) ;
		newDoc.setParentCategoryNames( references.getParents( id ) ) ;
		
		
		if( oldDoc != null )
		{			
			newDoc.setName( oldDoc.getName() ) ;
			newDoc.setCategory(oldDoc.getCategory()) ;
			ParsedProperty prop ;
			prop = oldDoc.getProperty( IPropertyConstants.WWW_PICTURE_LINKS_PROPERTY_NAME ) ;
			if( prop != null )
				newDoc.addProperty(prop) ;
			prop = oldDoc.getProperty( IPropertyConstants.WWW_PICTURE_COMMENTS ) ;
			if( prop != null )
				newDoc.addProperty(prop) ;
			prop = oldDoc.getProperty( IPropertyConstants.PICTURE_LIST_PROPERTY_NAME ) ;
			if( prop != null )
				newDoc.addProperty(prop) ;
		}
		
		parser.parseDocument( documentContent,DefaultParserProvider.getInstance(),this, newDoc ) ;		
		newDoc.extractLinks(category) ;
		
		if( oldDoc == null )
			category.addParsedDocument(newDoc) ;		
		else
			request.operate( oldDoc, newDoc ) ;
	}
	
	public void reparse(String id){
		LowLevelStorage.this.reparse(id, 0 ) ;
	}
	
	public void reparse(String id, int flags){
		doReparse(id, flags);
		
		new ProperyDataExtractor().extractProperties( this, 0) ;
		processTableInfo() ;
		save() ;
		parser.dispose() ;
	}

	protected void doReparse(String id, int flags) {
		reparseDocument( id,new ReplacementRequest(),flags);
	}
	
	abstract protected List<String> getDocumentList() ;
	
	public void reparseAll() {		
		
		category.clearLinks() ;
		//parallel for
//		Executor exec = Executors.newFixedThreadPool(4) ; 
		for ( String id : getDocumentList() ){
			//id="Mikoyan-Gurevich MiG-21" ;
			final String id_f = id ;
//			exec.execute( new Runnable(){

//				@Override
//				public void run() {
					doReparse(id_f, 0) ;				
//				}				
//			}) ;
			
		}

		new ProperyDataExtractor().extractProperties( this, 0);
		processTableInfo() ;
		save() ;
		parser.dispose() ;
	}

	public void extractCategory( String inputCategory )
	{
//		inputCategory = "Fighter aircraft" ;
		parseCategory( inputCategory, new ReplacementRequest(), 0 );//FORCE_REPARSE_FLAG  ) ;
		new ProperyDataExtractor().extractProperties(this, 0);
		XMLInterface.saveParsedCategory( this.rootPath + RAW_DATA_FILE_NAME, category, 0 );
	}
	
	//accepts FORCE_RELOAD_FLAG and FORCE_RELOAD_FLAG 
	public void parseCategory( String inputCategory, ReplacementRequest request, int flags  )
	{
		HashSet<String> processedDocuments = new HashSet<String>() ; 
		ArrayList<String> buffer = new ArrayList<String>() ;
		
		buffer.add( inputCategory ) ;
		
		for( int i = 0 ; i < buffer.size() ; i++ )
		{
			String documentName = buffer.get(i) ;
			if( processedDocuments.contains(documentName) )
				continue ;
			
			if( category.getParsedDocument(documentName)  != null &&
					( flags & FORCE_RELOAD_FLAG) + ( flags & FORCE_REPARSE_FLAG ) == 0 )
				continue ;
			
			reparseDocument(documentName, request,flags) ;
			
			

			for( String str : references.getChildren( documentName ) ){
				
				if( processedDocuments.contains( str ) )
					continue ;
				
				//TODO dirty hack here :-)
				if( badCategories.contains(str) )
					continue ;
			
//				String redirected = ParserV2.redirect(str) ;
//				if( redirected != null )
//					redirected = redirected.replace('_', ' ') ;
//				
//				else
//					redirected = str ;				
//				
//				if( badCategories.contains( redirected ) )
//					continue ;
				
				if( processedDocuments.contains( str ) )
					continue ;
				
				buffer.add( str ) ;				
			}
			
			processedDocuments.add( documentName ) ;
		}
		updateParentCategories() ;
		references.saveStorage() ;		
	}
	HashSet<String> badCategories = new HashSet<String>( Arrays.asList( new String[]{
		"Tank personnel",
		"Tank units and formations",
		"Military history of Italy during World War II"		
	}) ) ;
	
	public void setProperty(WikiStorageProperty prop) {
		if( prop == null || prop.pChar == null || prop.pChar.getName() == null )
			return ;
		
		PropertyCharacteristic pChar = prop.pChar ;
		String propertyName = pChar.getName() ;
		
//		if( category == null )
//			category = new ParsedCategory( this.rootPath ) ;
	
		category.getChracteristicsMap().put( propertyName, pChar ) ;
	}
	
	private void updateParentCategories() {		
		for( ParsedDocument doc : category.getDocumentsList() )
			doc.setParentCategoryNames( references.getParents( doc.getName() ) ) ;	
	}
	
	public Collection<String> getParents(String name) {
		return references.getParents(name);
	}

	public Collection<String> getChildren(String name) {
		return references.getChildren(name);
	}

	public String getRootPath() {
		final String crp = category.getRootPath();
		return crp + ( crp.endsWith("/")||crp.endsWith("\\") ? "" : "/" )  ;
	}
	
	public boolean save() {
		XMLInterface.saveParsedCategory( this.getRootPath() + RAW_DATA_FILE_NAME, category, 0 );
		return true ;
	}



}
